package org.jeecg.modules.meter.service.impl;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import org.apache.commons.lang.StringUtils;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.system.vo.LoginUser;
import org.jeecg.common.util.SsoUtil;
import org.jeecg.entity.meter.*;
import org.jeecg.enums.meter.MeterBindStatusEnum;
import org.jeecg.enums.meter.MeterChargeTypeEnum;
import org.jeecg.enums.meter.MeterSwitchStatusEnum;
import org.jeecg.enums.meter.MeterUseStatusEnum;
import org.jeecg.model.meter.reqvo.MeterDayReportReqVo;
import org.jeecg.model.meter.resvo.MeterUseListRespVo;
import org.jeecg.model.meter.resvo.MeterUseReportRespVo;
import org.jeecg.modules.message.entity.SysMessage;
import org.jeecg.modules.meter.entity.MeterRoom;
import org.jeecg.modules.meter.iot.entity.MeterBaseDto;
import org.jeecg.modules.meter.mapper.*;
import org.jeecg.modules.meter.service.IMeterChargeInfoService;
import org.jeecg.modules.meter.service.IMeterService;
import org.jeecg.modules.meter.service.MeterIotService;
import org.jeecg.vo.meter.FloorResVo;
import org.jeecg.vo.meter.MeterSmsRespVo;
import org.jeecg.vo.meter.roomResVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.validation.Valid;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;


/**
 * @Description: 水电表基础信息
 * @Author: jeecg-boot
 * @Date:   2020-11-20
 * @Version: V1.0
 */
@Service
public class MeterServiceImpl extends ServiceImpl<MeterMapper, Meter> implements IMeterService {
    @Autowired
    private MeterGatewayServiceImpl meterGatewayService;
    @Autowired
    private MeterFeeRuleServiceImpl meterFeeRuleService;
    @Autowired
    private MeterAccountMapper meterAccountMapper;
    @Autowired
    private MeterMapper meterMapper;
    @Autowired
    private MeterReadMapper meterReadMapper;
    @Autowired
    private MeterRoomServiceImpl meterRoomService;
    @Autowired
    private MeterFeeRuleMapper meterFeeRuleMapper;
    @Autowired
    private MeterFeeServiceImpl meterFeeService;
    @Autowired
    private MeterFeeMapper meterFeeMapper;
    @Autowired
    private MeterRoomMapper meterRoomMapper;
    @Autowired
    private  MeterChangeMapper meterChangeMapper;
    @Autowired
    private MeterAccountServiceImpl meterAccountService;
    @Autowired
    private MeterChargeInfoMapper meterChargeInfoMapper;
    @Autowired
    private IMeterChargeInfoService meterChargeInfoService;
    @Autowired
    private MeterIotService meterIotService;

    @Override
    public Result add(@Valid Meter meter) {
        return null;
    }

    @Override
    public List<Meter> findPage(Page<Meter> page, Meter meter) {
        return   meterMapper.findPage(page, meter);
    }

    @Override
    public List<MeterUseListRespVo> queryUseList() {
        return meterMapper.queryUseList();
    }

    @Override
    public Integer updateStatus(String meterId, Integer state, LoginUser loginUser) {
       return meterMapper.updateStatus(meterId,state,loginUser);
    }

    @Override
    public List<ReceiveList> getAddressList(String meterId) {
        return meterMapper.getAddressList(meterId);
    }

    @Override
    public List<MeterRead> historyRead(String meterId) {
        return meterMapper.historyRead(meterId);
    }

    @Override
    public List<Meter> queryMeterList(List<String> asList) {
        return meterMapper.queryMeterList(asList);
    }

    @Override
    public boolean deleteByMeterId(String id) {
      return   meterMapper.deleteByMeterId(id)>0?true:false;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean editMeter(Meter meter) {
        StringBuilder sb = new StringBuilder();
        Meter oldMeter = meterMapper.selectById(meter.getId());
        //判断表号是否改变
        if(!oldMeter.getMeterCode().equals(meter.getMeterCode()) && oldMeter.getSyncStatus() == 1){
            MeterGateway meterGateWay = meterGatewayService.getByMeterId(meter.getId());
            if (null == meterGateWay){
                return  false;
            }
            MeterBaseDto meterBaseDto = meterIotService.saveMeterBase(meter.getMeterKey(),meter.getMeterCode(),meter.getCollectorAddress(),meter.getMeterType(),"",meterGateWay.getRequestUrl(),meterGateWay.getIotType());

            if (null == meterBaseDto){
                 return  false;
            }
        }
        //判断倍率是否改变
        if ( oldMeter.getRate() != meter.getRate() ){
            //重新计算使用量 金额
            ArrayList<String> meterIdList = Lists.newArrayList();
            meterIdList.add(meter.getId());
                List<MeterRead> lastMeterReads = meterReadMapper.findLastMeterReads(meterIdList);
             //有过历史读数
             if (lastMeterReads.size() > 0){
                 MeterFeeRule meterFeeRule = meterFeeRuleService.queryFeeByMeterId(meter.getId());
                 BigDecimal price = meterFeeRule.getFeePrice();
                 Integer roundMode = meterFeeRule.getRoundMode();
                 Integer precision = meterFeeRule.getFeePrecision();
                 MeterRead oldMeterRead = lastMeterReads.get(0);
                 BigDecimal nowRead = new BigDecimal(oldMeterRead.getNowRead());
                 //最新读数
                 BigDecimal oldRead = new BigDecimal(oldMeterRead.getNowRead());
                 BigDecimal oldPreRead = new BigDecimal(oldMeterRead.getPreRead());
                  //更改后的倍率
                 BigDecimal newRate = new BigDecimal(meter.getRate());
                 //计算最新使用量
                 BigDecimal nowUse = nowRead.multiply(newRate).subtract(nowRead.multiply(new BigDecimal(oldMeter.getRate())));
                 MeterRead meterRead = new MeterRead();
                 meterRead.setMeterId(meter.getId());
                 meterRead.setNowRead(oldRead.toString());
                 meterRead.setNowUse(nowUse.toString());
                 meterRead.setPreRead(oldPreRead.toString());
                 meterRead.setRate(Integer.valueOf(newRate.toString()));
                 meterRead.setCreateTime(new Date());
                 meterRead.setPrice(price.toString());
                 meterRead.setIsRate(0);
                 meterRead.setTenantId(meter.getTenantId());
                 meterReadMapper.insert(meterRead);
                 MeterAccount meterAccount = meterAccountMapper.getByMeterId(meter.getId());
                 MeterChargeInfo meterChargeInfo = new MeterChargeInfo();
                 //获取仪表对应收费单价
                 BigDecimal newNowUse = new BigDecimal(meterRead.getNowUse());
                 meterChargeInfo.setChargeType(MeterChargeTypeEnum.METER_CHARGE_TYPE_ISRATE.getCode());
                 meterChargeInfo.setMeterReadId(meterRead.getId());
                 meterChargeInfo.setMeterId(meter.getId());
                 meterChargeInfo.setChargeTime(new Date());
                 meterChargeInfo.setChargeUse(newNowUse.toString());
                 BigDecimal chargeAmount = price.multiply(newNowUse);
                 BigDecimal realChargeAmount = BigDecimal.ZERO.subtract(chargeAmount);
                 meterChargeInfo.setChargeAmount(realChargeAmount.setScale(precision,roundMode).toString());
                 //计算剩余用量
                 //剩余金额
                 BigDecimal remainAmount = meterAccount.getRemainAmount() == null ? BigDecimal.ZERO : new BigDecimal(meterAccount.getRemainAmount());
                 //计算剩余金额
                 BigDecimal newAmount = nowUse.multiply(price);
                 BigDecimal lastRemainAmount = remainAmount.subtract(newAmount);
                 meterChargeInfo.setTenantId(meter.getTenantId());
                 meterChargeInfo.setRemainAmount(lastRemainAmount.setScale(precision,roundMode).toString());
                 meterChargeInfoMapper.insert(meterChargeInfo);
                 //更新账户
                 MeterAccount newMeterAccount = new MeterAccount();
                 newMeterAccount.setTotalUse(oldRead.toString());
                 newMeterAccount.setRemainAmount(lastRemainAmount.setScale(precision,roundMode).toString());
                 //计算剩余量
                 BigDecimal remainUse = lastRemainAmount.divide(price.multiply(new BigDecimal(oldMeter.getLoss())),precision);
                 newMeterAccount.setRemainUse(remainUse.toString());
                 newMeterAccount.setMeterId(oldMeter.getId());
                 meterAccountMapper.updateAmount(newMeterAccount);
             }
        }
        //删除原有绑定房间
        meterMapper.deleteByMeterId(meter.getId());
        //重新绑定房间
        ArrayList<MeterRoom> meterRoomList = Lists.newArrayList();
        ArrayList<MeterFee> meterFeeList = new ArrayList<>();
        if (meter.getFloorIdList() != null){
            for (int a = 0; a < meter.getFloorIdList().size(); a++) {
                MeterRoom meterRoom = new MeterRoom();
                meterRoom.setMeterId(meter.getId());
                meterRoom.setBuildingId(meter.getFloorIdList().get(a));
                meterRoom.setProjectId(meter.getProjectId());
                meterRoom.setIsBind(MeterBindStatusEnum.METER_BIND_STATUS_YES.getCode());
                if (StringUtils.isNotEmpty(meter.getRoomIdList().get(a))){
                    meterRoom.setRoomId(meter.getRoomIdList().get(a));
                }
                meterRoomList.add(meterRoom);
            }
            meterRoomService.saveBatch(meterRoomList);
        }
        //删除旧收费项
        meterFeeMapper.deleteByMeterId(meter.getId());
        if (meter.getPayItem() != null ){
            for (String meterFeeRuleId : meter.getPayItem()) {
                MeterFee meterFee = new MeterFee();
                meterFee.setMeterId(meter.getId());
               // meterFee.setTenantId(meter.getTenantId());
                meterFee.setFeeRuleId(meterFeeRuleId);
                meterFee.setProjectId(meter.getProjectId());
                meterFee.setIsBind(MeterBindStatusEnum.METER_BIND_STATUS_YES.getCode());
                meterFeeList.add(meterFee);
            }
            meterFeeService.saveBatch(meterFeeList);
        }
//           meter.setUpdateTime(new Date());
//         return   meterMapper.updates(meter)>0;
        return  meterMapper.updateById(meter)>0;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Integer changeMeter(Meter meter) {
        Meter oldMeter = meterMapper.selectById(meter.getId());
        //获取旧表绑定收费项
        List<MeterFee> meterFees = meterFeeMapper.queryFeeList(1, oldMeter.getId());
        //获取旧表绑定地址
        List<MeterRoom> meterRooms = meterRoomMapper.queryOldMeterAddress(oldMeter.getId());
        Integer count = meterGatewayService.queryCountByWayNo(meter.getMeterCode(), meter.getMeterGateway());
        if (count > 0) {
            return 0;
        }

        meter.setId(null);
        meter.setTenantId(oldMeter.getTenantId());
        meterMapper.insert(meter);
        String MeterId = meter.getId();
        //绑定收费房间
        if (null !=meterRooms) {
                for (MeterRoom meterRoom:meterRooms){
                    meterRoom.setProjectId(meter.getProjectId());
                    meterRoom.setId(null);
                    meterRoom.setMeterId(MeterId);
                    meterRoom.setIsBind(MeterBindStatusEnum.METER_BIND_STATUS_YES.getCode());
                    meterRoom.setCreateTime(new Date());
                    meterRoom.setUpdateTime(new Date());
                }
        } else {
            meterRooms.clear();
            MeterRoom meterRoom = new MeterRoom();
            meterRoom.setProjectId(meter.getProjectId());
            meterRoom.setMeterId(MeterId);
            meterRoom.setIsBind(MeterBindStatusEnum.METER_BIND_STATUS_YES.getCode());
            meterRooms.add(meterRoom);
        }
        //绑定收费项
              for (MeterFee meterFee : meterFees) {
                meterFee.setMeterId(MeterId);
                meterFee.setId(null);
                meterFee.setTenantId(oldMeter.getTenantId());
                meterFee.setProjectId(meter.getProjectId());
                meterFee.setIsBind(MeterBindStatusEnum.METER_BIND_STATUS_YES.getCode());
                meterFee.setCreatedTime(new Date());
                meterFee.setUpdatedTime(new Date());
            }
            meterFeeService.saveBatch(meterFees);
           meterRoomService.saveBatch(meterRooms);
           MeterAccount meterAccount = new MeterAccount();
           meterAccount.setMeterId(meter.getId());
           meterAccount.setTenantId(oldMeter.getTenantId());
           meterAccount.setTotalUse("0");  //初始时
           meterAccount.setPayAmount("0");
           meterAccount.setRemainAmount(meter.getBeginAmount());
           meterAccount.setRemainUse(meter.getBeginUse());
           int save = meterAccountMapper.insert(meterAccount);
          //获取旧表 使用信息
        MeterAccount ma = meterAccountMapper.getByMeterId(oldMeter.getId());
        if (ma != null){
            MeterChange meterChange = new MeterChange();
            meterChange.setMeterNewId(MeterId);
            meterChange.setTenantId(oldMeter.getTenantId());
            meterChange.setMeterOldId(oldMeter.getId());
            meterChange.setOldRemainAmount(ma.getRemainAmount());
            meterChange.setOldRemainUse(ma.getRemainUse());
            meterChange.setNewBeginAmount(meter.getBeginAmount());
            meterChange.setNewBeginUse(meter.getBeginUse());
            meterChangeMapper.insert(meterChange);
        }
        //更新旧表为已换表
        LoginUser loginUser = SsoUtil.getLoginUser();
        meterMapper.updateStatus(oldMeter.getId(), MeterUseStatusEnum.USE_CHANGE.getCode(),loginUser);
        //解绑旧表绑定收费项
        meterFeeMapper.untieFeeByMeterId(oldMeter.getId());
        return save;
    }

    @Override
    public String queryProjectName(String projectId) {
        return meterMapper.queryProjectName(projectId);
    }

    @Override
    public String queryFloorName(String projectId, String trim) {
        return meterMapper.queryFloorName(projectId,trim);
    }

    @Override
    public String queryRoomName(String floorId, String trim) {
        return meterMapper.queryRoomName(floorId,trim);
    }

    @Override
    public void saveBatchExcel(List<Meter> meterList) {
        LoginUser loginUser = SsoUtil.getLoginUser();
        List<Meter> meterAddList = Lists.newArrayList();
        List<MeterRoom> meterAddress = Lists.newArrayList();
        List<MeterAccount> meterAccountList = Lists.newArrayList();
        List<MeterFee> meterFeeList = Lists.newArrayList();
        for (Meter meter : meterList) {
            meter.setId(UUID.randomUUID().toString().replace("-", ""));
            meter.setTenantId(meter.getMeterAddressAddVo().getTenantId());
            meter.setCreateBy(loginUser.getRealname());
            meter.setCreateTime(new Date());
            meter.setRemarks("Importer");
            meter.setWarningStatus(0);
            meter.setSwitchStatus(MeterSwitchStatusEnum.METER_SWITCH_STATUS_ON.getCode());
            meter.setUseStatus(MeterUseStatusEnum.USE_NORMAL.getCode());
            meter.setOnlineStatus(1);
            meter.setLoss(meter.getLoss().toString());
            meterAddList.add(meter);
            //账号余额表
            MeterAccount meterAccount = new MeterAccount();
            meterAccount.setMeterId(meter.getId());
            meterAccount.setMeterCode(meter.getMeterCode());
            meterAccount.setRemainAmount(meter.getBeginAmount());
            meterAccount.setRemainUse(meter.getBeginUse());
            meterAccount.setTotalUse("0");
            meterAccount.setTenantId(meter.getMeterAddressAddVo().getTenantId());
            meterAccount.setPayAmount("0");
            meterAccountList.add(meterAccount);
            //绑定地址
            MeterRoom meterRoom= new MeterRoom();
            meterRoom.setMeterId(meter.getId());
            meterRoom.setIsBind(1);
            if (StringUtils.isNotEmpty(meter.getMeterAddressAddVo().getProjectId())){
                meterRoom.setProjectId(meter.getMeterAddressAddVo().getProjectId());
            }else {
                meterRoom.setProjectId("");
            }
            if (StringUtils.isNotEmpty(meter.getMeterAddressAddVo().getFloorId())){
                meterRoom.setBuildingId(meter.getMeterAddressAddVo().getFloorId());
            }else {

                meterRoom.setBuildingId("");
            }
            if (StringUtils.isNotEmpty(meter.getMeterAddressAddVo().getRoomId())){
                meterRoom.setRoomId(meter.getMeterAddressAddVo().getRoomId());
            }else {
                meterRoom.setRoomId("");
            }
            meterAddress.add(meterRoom);
            for (String feeId:meter.getPayItem()){
                MeterFee mf = new MeterFee();
                mf.setTenantId(meter.getTenantId());
                mf.setProjectId(meter.getProjectId());
                mf.setFeeRuleId(feeId);
                mf.setMeterId(meter.getId());
                mf.setIsBind(1);
                meterFeeList.add(mf);
            }
        }
        meterFeeService.saveBatch(meterFeeList);
        meterRoomService.saveBatch(meterAddress);
        meterAccountService.saveBatch(meterAccountList);
        this.saveBatch(meterList);
    }

    @Override
    public Meter getSelfById(String meterId) {
        return meterMapper.getSelfById(meterId);
    }

    @Override
    public List<Meter> findByIds(List<String> ids) {
        return meterMapper.findByIds(ids);
    }

    @Override
    public int updateSyncStatus(String id, String meterKey) {
        return meterMapper.updateSyncStatus(id,meterKey);
    }

    @Override
    public List<MeterUseReportRespVo> findGroupList(MeterDayReportReqVo meterDayReportReqVo) {
        return meterMapper.findGroupList(meterDayReportReqVo);
    }


    @Override
    public  List<Meter>  findMeterList() {
        return meterMapper.findMeterList();
    }

    @Override
    public String queryTenantId(String projectId) {
        return meterMapper.queryTenantId(projectId);
    }

    @Override
    public List<MeterSmsRespVo> queryMeterSms() {
        return meterMapper.queryMeterSms();
    }

    @Override
    public SysMessage querySmsIsSend(String meterId) {
        return meterMapper.querySmsIsSend(meterId);
    }

    @Override
    public List<roomResVo> queryRoomList(String projectId) {
        return meterMapper.queryRoomList(projectId);
    }   @Override
    public List<FloorResVo> queryFloorList(String projectId) {
        return meterMapper.queryFloorList(projectId);
    }

    @Override
    public boolean collectorAddressBatch(List<String> meterIds,String collector) {
        return meterMapper.collectorAddressBatch(meterIds,collector)>=1?true:false;
    }

    @Override
    public List<String> getCollectorAddress(List<String> meterIds) {
        return meterMapper.getCollectorAddress(meterIds);
    }

    @Override
    public List<String> queryFeeItemNameByMeterId(String id) {

        return meterFeeMapper.queryFeeItemNameByMeterId(id);
    }

    @Override
    public Integer queryCountMeterCode(String meterCode) {
        return meterMapper.queryCountMeterCode(meterCode);
    }

    @Override
    public Result<?> repairRead(MeterRead oldMeterRead, MeterChargeInfo meterChargeInfo, BigDecimal preRead) {
        BigDecimal oldPreRead = new BigDecimal(oldMeterRead.getPreRead());
        BigDecimal oldNowRead = new BigDecimal(oldMeterRead.getNowRead());
        BigDecimal rate = new BigDecimal(oldMeterRead.getRate());
        BigDecimal price = new BigDecimal(oldMeterRead.getPrice());
        if (preRead.compareTo(oldNowRead) > 0) return Result.error("不可大于本次读数！");
        //计算差量
        BigDecimal diffUse = preRead.subtract(oldPreRead).multiply(rate);
        //计算差额
        BigDecimal diffAmount = diffUse.multiply(price).divide(BigDecimal.ONE,2,BigDecimal.ROUND_HALF_UP);
        //计算用量
        BigDecimal use = oldNowRead.subtract(preRead).multiply(rate);
        oldMeterRead.setPreRead(preRead.toString());
        oldMeterRead.setNowUse(use.toString());

        //原先的变动金额(负数)
        BigDecimal oldChargeAmount = new BigDecimal(meterChargeInfo.getChargeAmount());
        meterChargeInfo.setChargeAmount(oldChargeAmount.add(diffAmount).toString());
        meterChargeInfo.setChargeUse(preRead.toString());
        //剩余额
        BigDecimal oldRemainAmount = new BigDecimal(meterChargeInfo.getRemainAmount());
        oldRemainAmount = oldRemainAmount.add(diffAmount);
        meterChargeInfo.setRemainAmount(oldRemainAmount.toString());

        //后面的历史扣费记录也要变动
        List<MeterChargeInfo> hisChargeInfoList =  meterChargeInfoService.findHisByMeterId(oldMeterRead.getMeterId(),meterChargeInfo.getChargeTime(), MeterChargeTypeEnum.METER_CHARGE_TYPE_DOCK.getCode());

        //账号剩余额
        MeterAccount meterAccount =  meterAccountService.getByMeterId(oldMeterRead.getMeterId());
        if (meterAccount == null ) return Result.error("无仪表账号！");
        BigDecimal oldRemainAmount2 = new BigDecimal(meterAccount.getRemainAmount());
        BigDecimal oldRemainUse2 = new BigDecimal(meterAccount.getRemainUse());
        oldRemainUse2 = oldRemainUse2.add(diffUse);
        oldRemainAmount2 = oldRemainAmount2.add(diffAmount);
        meterAccount.setRemainAmount(oldRemainAmount2.toString());
        meterAccount.setRemainUse(oldRemainUse2.toString());

        //更新数据
        meterReadMapper.updateRepairRead(oldMeterRead);
        meterChargeInfoMapper.updateRepairRead(meterChargeInfo);
        meterAccountService.updateRepairRead(meterAccount);
        for (MeterChargeInfo info:hisChargeInfoList){
            BigDecimal oldRemainAmountTemp = new BigDecimal(info.getRemainAmount());
            oldRemainAmountTemp = oldRemainAmountTemp.add(diffAmount);
            info.setRemainAmount(oldRemainAmountTemp.toString());
            meterChargeInfoMapper.updateRepairRead(info);
        }

        return Result.ok();
    }

    @Override
    public Integer queryMeterUseCount() {
        return meterMapper.queryMeterUseCount();
    }

    @Override
    public void saveMeterMonthUse(List<MeterUseListRespVo> meterUseListRespVos) {
        meterMapper.saveMeterMonthUse(meterUseListRespVos);
    }

    @Override
    public List<MeterUseListRespVo> getMeterMonthUse() {
       return meterMapper.getMeterMonthUse();
    }

    @Override
    public void updateMonthMeterUse(List<MeterUseListRespVo> meterUseListRespVos) {
        meterMapper.updateMonthMeterUse(meterUseListRespVos);
    }

    @Override
    public List<MeterChargeInfo> getMeterPayRecord(String meterId) {
        return meterMapper.getMeterPayRecord(meterId);
    }


    @Override
    public void updateSwitchStatus(Meter meter) {
        meterMapper.updateSwitchStatus(meter);
    }
}

